home *** CD-ROM | disk | FTP | other *** search
- /*
- *
- * blt2cx01.c - 17-Oct-1995 Cornel Huth
- * This module is called by blt2demo.c
- * REINDEX_XB
- * 25-Feb-96:
- */
-
- #include "platform.h"
-
- #ifdef ON_OS2
- #define INCL_DOSPROCESS // for OS/2 threads
- #include <os2.h>
- #endif
- #ifdef ON_W95
- #define WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #endif
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <time.h>
- #include <string.h>
-
- #ifdef ON_OS2
- #include "bullet2.h"
- #endif
- #ifdef ON_W95
- #include "bullet95.h"
- #endif
- #ifdef ON_DOSX
- #include "bulletx.h"
- #endif
-
-
- void cx01BuildFieldList(FIELDDESCTYPE fieldList[]);
-
-
- #ifdef ON_OS2
- LONG reindexRez=0; // thread reindex return code
- TID tidReindex; // reindex thread ID
- VOID APIENTRY ReindexThread(ACCESSPACK *AP);
- #endif
- #ifdef ON_W95
- LONG reindexRez=0; // thread reindex return code
- DWORD tidReindex; // reindex thread ID
- HANDLE hReindex; // reindex thread's handle
- VOID APIENTRY ReindexThread(ACCESSPACK *AP);
- #endif
-
- extern CHAR *collateTable;
-
-
- int cx01(void) {
-
- #pragma pack(1)
-
- ACCESSPACK AP;
- DOSFILEPACK DFP;
- CREATEDATAPACK CDP;
- CREATEINDEXPACK CIP;
- HANDLEPACK HP;
- OPENPACK OP;
- QUERYSETPACK QSP;
-
- #if defined ON_OS2 || defined ON_W95
- STATINDEXPACK SIP; // for reindex percentage done, needs thread support
- #endif
-
- struct EmpRecType {
- CHAR tag; // record tag, init to SPACE, * means deleted
- CHAR empID[9]; // SSN (not 0T string)
- CHAR empLN[16]; // last name
- CHAR empFN[16]; // first name
- CHAR empHire[8]; // "YYYYMMDD" (not 0T string)
- CHAR empDept[6]; // department assigned
- }; // 56 bytes
- struct EmpRecType EmpRec;
-
- #pragma pack()
-
- time_t startTime, endTime;
- int display = 0; // display results or not flag
- int thread = 1; // dispatch reindex in a thread flag
- int lastNameVar = 0; // used to construct on-the-fly data record...
- int lastFourVar = 0; // ...that is unique
-
- LONG rez; // return value from Bullet
-
- CHAR nameIX3[] = "$CX01.IX3"; // name of index file created
- ULONG indexID=0; // handle of index file
- CHAR keyExpression[128]; // key expression string buffer (159 max)
- CHAR keyBuffer[68]; // buffer used to store/receive key values
-
- CHAR nameData[] = "$CX01.DBF"; // name of data file created
- ULONG dataID=0; // handle of data file
- FIELDDESCTYPE fieldList[5]; // 5 fields used in data record
-
- LONG recs2add; // records to add en-masse
- LONG i; // counter
- CHAR tmpStr[64]; // misc stuff, non-Bullet related
-
- #define NEW_XBUFF_SIZE (384*1024) // use 384KB for reindex buffer workspace
-
-
- memset(fieldList,0,sizeof(fieldList)); // init unused bytes to 0 (required)
- cx01BuildFieldList(fieldList);
-
-
- // Use 384K for workspace in reindex module
-
- QSP.func = SET_SYSVARS_XB;
- QSP.item = REINDEX_BUFFER_SIZE;
- QSP.itemValue = NEW_XBUFF_SIZE;
- rez = BULLET(&QSP);
- if (rez) {
- printf("Failed SET_SYSVARS call. Err: %li\n",rez);
- goto Abend;
- }
- printf("Bullet reindex tmp buffer was %ld KB, now %ld KB (0 KB means default, 144KB)\n",
- QSP.itemValue/1024,NEW_XBUFF_SIZE/1024);
-
- // Delete previous files from any previous run (disregard any error return)
-
- DFP.func = DELETE_FILE_DOS;
- DFP.filenamePtr = nameData;
- rez = BULLET(&DFP);
- DFP.filenamePtr = nameIX3;
- rez = BULLET(&DFP);
-
-
- // Create the data file, a standard DBF (ID=3) as defined in fieldList above.
-
- CDP.func = CREATE_DATA_XB;
- CDP.filenamePtr = nameData;
- CDP.noFields = 5;
- CDP.fieldListPtr = fieldList;
- CDP.fileID = 0x03;
- rez = BULLET(&CDP);
- if (rez) {
- printf("Failed data file create. Err: %li\n",rez);
- goto Abend;
- }
-
-
- // Open the data file (required before creating an index file for it)
-
- OP.func = OPEN_DATA_XB;
- OP.filenamePtr = nameData;
- OP.asMode = READWRITE | DENYNONE;
- rez = BULLET(&OP);
- if (rez) {
- printf("Failed data file open. Err: %li\n",rez);
- goto Abend;
- }
- dataID = OP.handle;
-
-
- // Create an index file for the data file opened above.
- // This example uses a multi-part key composed of parts of last name and SSN.
-
- strcpy(keyExpression,"SUBSTR(LNAME,1,4)+SUBSTR(SSN,6,4)");
-
- CIP.func = CREATE_INDEX_XB;
- CIP.filenamePtr = nameIX3;
- CIP.keyExpPtr = keyExpression;
- CIP.xbLink = dataID; // the handle of the data file
- CIP.sortFunction = NLS_SORT; // sort by NLS
- CIP.codePage = CODEPAGE; // code page to use, or 0 for system default
- CIP.countryCode = CTRYCODE; // country code...
- CIP.collatePtr = collateTable; // (see #define INT2165xxNS above)
- CIP.nodeSize = 512; // 512-byte node size (or 1024, 2048 bytes)
- rez = BULLET(&CIP);
- if (rez) {
- printf("Failed index file create. Err: %li\n",rez);
- goto Abend;
- }
-
-
- // Open the index file (what we just created above).
- // As with the index-create, the index-open requires the handle of the data
- // file which this index file indexes.
-
- OP.func = OPEN_INDEX_XB;
- OP.filenamePtr = nameIX3;
- OP.asMode = READWRITE | DENYNONE;
- OP.xbLink = dataID;
- rez = BULLET(&OP);
- if (rez) {
- printf("Failed index file open. Err: %li\n",rez);
- goto Abend;
- }
- indexID = OP.handle;
-
-
- printf("Display all data accessed (slower results)? (y/N) ");
- gets(tmpStr);
- if (*tmpStr=='y') display = 1;
-
- #if defined ON_OS2 || defined ON_W95
- printf(" Dispatch REINDEX_XB in a separate thread? (Y/n) ");
- gets(tmpStr);
- if (*tmpStr=='n') thread = 0;
- #else
- thread = 0;
- #endif
-
- printf(" How many records do you want for this test run? ");
- gets(tmpStr);
- recs2add = atol(tmpStr);
- if (recs2add < 1) recs2add = 1; // would you rather end the test?
- if (recs2add > 9999999) recs2add = 1; // why wait around for 10M?
-
-
- // Add the data records, which are created here, on-the-fly, varying enough
- // to make unique records.
-
- EmpRec.tag = ' '; // set to not-deleted
- strncpy(EmpRec.empID,"465990000",9); // only changing last 4 in test
- strcpy(EmpRec.empLN,"0000LastNameNum"); // only changing first 4 in test
- strcpy(EmpRec.empFN,"YourFirstName"); // everyone has this first name!
- strncpy(EmpRec.empHire,"19950527",8); // YYYYMMDD DBF form, no \0 on date
- strcpy(EmpRec.empDept,"MIS"); // everyone works for MIS!
-
- printf(" Adding %ld records... ",recs2add);
- time(&startTime);
-
- AP.func = ADD_RECORD_XB;
- AP.handle = dataID;
- AP.recPtr = &EmpRec;
- for (i = 1; i <= recs2add; i++) {
-
- sprintf(tmpStr,"%4.4i",lastFourVar++);
- strncpy(EmpRec.empID+5,tmpStr,4); // update last 4 of empID
- rez = BULLET(&AP); // AP. already setup
- if (rez) {
- printf("Failed while adding record %ld. Err: %li\n",i,rez);
- goto Abend;
- }
- if (lastFourVar > 9999) { // changes every 10,000 adds
- lastFourVar = 0;
- sprintf(tmpStr,"%4.4i",++lastNameVar);
- strncpy(EmpRec.empLN,tmpStr,4); // update first 4 of empLN
- }
- }
- time(&endTime);
- printf("took %lu secs.\n",(endTime - startTime));
-
-
- // Reindex
-
- printf("Reindexing %ld records... \r",recs2add);
- time(&startTime);
-
- AP.func = REINDEX_XB; // this is all there is to reindexing even...
- AP.handle = indexID; // ...million-record databases
- AP.keyPtr = keyBuffer; // if dup key error...(see manual for details)
- AP.nextPtr = NULL; // just this one index file
-
- if (thread) {
-
- #ifdef ON_OS2
-
- rez = DosCreateThread(&tidReindex,
- (PFNTHREAD) &ReindexThread,
- (ULONG) &AP,
- CREATE_READY | STACK_SPARSE,
- 32768); // can get by with much less stack, even 8KB
- if (rez) {
- printf("Could not start reindex thread. Err: %lu\n",rez);
- goto Abend;
- }
-
- DosSleep(1); // wait a bit to let reindex code set progress to non-zero
-
- SIP.func = STAT_INDEX_XB;
- SIP.handle = indexID;
- rez = BULLET(&SIP);
- while (rez==0) {
- DosSleep(100);
- printf("Reindexing %ld records... %3.3lu%%\r",recs2add,SIP.progress);
- rez = BULLET(&SIP);
- if (SIP.progress==0) {
- printf("Reindexing %ld records... ",recs2add);
- break;
- }
- }
- if (rez)
- printf("\nFailed progress check. Err: %li\n",rez);
-
- // Can actually get here _before_ the reindex thread fully exits, but
- // won't get here until SIP.progress is back to 0.
-
- time(&endTime);
-
- // It's likely that the thread has exited completely by now, but if
- // it was blocked after setting SIP.progress to 0 (hung up in the cache,
- // etc.), then it's possible to get here well before Bullet has exited.
- // Since calling Bullet while Bullet is busy (for most routines) results
- // in a rc=640 being returned (mutex timeout), just call this to wait
- // for the thread to exit completely. Note that this has only been seen
- // under Win95 (done, but blocked), but this little routine won't hurt.
- // Ignore any error, which there will be if the thread has indeed exited.
- // Another option is to use a non-0 mutex-timeout value, via SET_SYSVARS_XB.
-
- rez = DosWaitThread(&tidReindex,DCWW_WAIT);
- // ignore error (such as "invalid thread ID")
-
- DosSleep(1); // allow the reindex thread to exit BULLET() (and set rez)
-
- rez = reindexRez; // get return code set by ReindexThread()
- if (rez) { // rez is already AP.stat
- printf("Failed reindex. Err: %li\n",rez);
- goto Abend;
- }
- printf("took %lu secs.\n",(endTime - startTime));
-
- #endif
- #ifdef ON_W95
-
- hReindex = CreateThread(NULL,
- 32768, // 8KB min.
- (LPTHREAD_START_ROUTINE) &ReindexThread,
- (PACCESSPACK) &AP,
- 0, // immediate start
- &tidReindex);
-
-
- if (hReindex==0) {
- rez = GetLastError();
- printf("Could not start reindex thread. Err: %lu\n",rez);
- goto Abend;
- }
-
- Sleep(32); // wait a bit to let reindex code set progress to non-zero
-
- SIP.func = STAT_INDEX_XB;
- SIP.handle = indexID;
- rez = BULLET(&SIP);
- while (rez==0) {
- Sleep(100);
- printf("Reindexing %ld records... %3.3lu%%\r",recs2add,SIP.progress);
- rez = BULLET(&SIP);
- if (SIP.progress==0) {
- printf("Reindexing %ld records... ",recs2add);
- break;
- }
- }
- if (rez)
- printf("\nFailed progress check. Err: %li\n",rez);
-
- // Can actually get here _before_ the reindex thread fully exits, but
- // won't get here until SIP.progress is back to 0.
-
- time(&endTime);
-
- // It's likely that the thread has exited completely by now, but if
- // it was blocked after setting SIP.progress to 0 (hung up in the cache,
- // etc.), then it's possible to get here well before Bullet has exited.
- // Since calling Bullet while Bullet is busy (for most routines) results
- // in a rc=640 being returned (mutex timeout), just call this to wait
- // for the thread to exit completely. Note that this has only been seen
- // under Win95 (done, but blocked), but this little routine won't hurt.
- // Ignore any error, which there will be if the thread has indeed exited.
- // Another option is to use a non-0 mutex-timeout value, via SET_SYSVARS_XB.
- // Error code 640 is documented in BULLET95.H.
-
- rez = WaitForSingleObject(hReindex,10*1000); // 10 secs plenty of flush time
- // ignore error
-
- Sleep(32); // allow the reindex thread to exit BULLET() (and set rez)
- // why 32ms? Only because OS/2 min std resolution is 32ms
-
- rez = reindexRez; // get return code set by ReindexThread()
- if (rez) { // rez is already AP.stat
- printf("Failed reindex. Err: %li\n",rez);
- goto Abend;
- }
- printf("took %lu secs.\n",(endTime - startTime));
-
- #endif
- #ifdef ON_DOSX
-
- printf(" Threads are not supported on this OS\n");
- goto Abend;
-
- #endif
-
- }
- else {
- rez = BULLET(&AP);
- if (rez) { // rez is 1 or 0 (cannot be negative here)
- rez = AP.stat;
- printf("Failed reindex. Rez: %li Err: %li\n",rez, AP.stat);
- goto Abend;
- }
- time(&endTime);
- printf("Reindexing %ld records... took %lu secs.\n",
- recs2add,
- (endTime-startTime));
- }
-
-
- // Get key data
-
- memset(keyBuffer,0,sizeof(keyBuffer));
- printf(" Accessing %ld keys... ",recs2add);
- if (display) printf("\n");
- time(&startTime);
- AP.func = FIRST_KEY_XB;
- AP.handle = indexID;
- AP.keyPtr = keyBuffer;
- rez = BULLET(&AP);
- i=0;
- while (rez==0) {
- if (display) printf("%s %9.9lu\r", keyBuffer, AP.recNo);
- i++;
- AP.func = NEXT_KEY_XB;
- rez = BULLET(&AP);
- };
- if (display) printf("\n...");
-
- // expected rez is EXB_END_OF_FILE
-
- if (rez!=EXB_END_OF_FILE) {
- printf("Failed KEY access. Err: %li\n",rez);
- goto Abend;
- }
- time(&endTime);
- printf("took %lu secs. for %ld keys\n",(endTime - startTime),i);
-
-
- // Get key and record data
-
- printf(" Accessing %ld keys+recs...",recs2add);
- if (display) printf("\n");
- time(&startTime);
- AP.func = GET_FIRST_XB;
- AP.handle = indexID;
- AP.keyPtr = keyBuffer;
- AP.recPtr = &EmpRec;
- rez = BULLET(&AP);
- i=0;
- while (rez==0) {
- if (display)
- printf("%s %9.9lu %s\r", keyBuffer, AP.recNo, &EmpRec); // partial show
- i++;
- AP.func = GET_NEXT_XB;
- rez = BULLET(&AP);
- };
- if (display) printf("\n...");
-
- // expected rez is EXB_END_OF_FILE
-
- if (rez!=EXB_END_OF_FILE) {
- printf("Failed GET access. Err: %li\n",rez);
- goto Abend;
- }
- time(&endTime);
- printf("took %lu secs. for %ld keys & records\n",(endTime - startTime),i);
-
-
- // Fatal errors above come straight to here
- Abend:
-
- // Close files
-
- if (indexID) {
- HP.func = CLOSE_INDEX_XB;
- HP.handle = indexID;
- rez = BULLET(&HP);
- if (rez)
- printf("Failed index file close. Err: %li\n",rez);
- }
-
- // Unlikely the above could fail, considering how far it has gotten so far!
- // But logic says that we want to continue closing other open files...
-
- if (dataID) {
- HP.func = CLOSE_DATA_XB;
- HP.handle = dataID;
- rez = BULLET(&HP);
- if (rez)
- printf("Failed data file close. Err: %li\n",rez);
- }
-
- return rez; // module exit
- }
-
-
- #if defined ON_OS2 || defined ON_W95
-
- // -------------------------
- // Reindex thread, thread #2
-
- void APIENTRY ReindexThread(ACCESSPACK *AP) {
-
- reindexRez = BULLET(AP);
-
- // Reindex is a xaction-list routine and so must check AP.stat for any
- // error code -- rez as returned from the Bullet call is the list item
- // that failed. Since this example has but the single item, rez=1 on
- // failure, with the error code in AP.stat.
-
- if (reindexRez) {
- reindexRez = AP->stat;
- }
- }
- #endif
-
-
- //------------------------------------
- // Init field list items for data file
-
- void cx01BuildFieldList(FIELDDESCTYPE fieldList[]) {
-
- strcpy(fieldList[0].fieldName, "SSN"); // field names must be upper-case
- fieldList[0].fieldType = 'C'; // field types must be upper-case
- fieldList[0].fieldLen = 9;
- fieldList[0].fieldDC = 0;
-
- strcpy(fieldList[1].fieldName, "LNAME");
- fieldList[1].fieldType = 'C';
- fieldList[1].fieldLen = 16;
- fieldList[1].fieldDC = 0;
-
- strcpy(fieldList[2].fieldName, "FNAME");
- fieldList[2].fieldType = 'C';
- fieldList[2].fieldLen = 16;
- fieldList[2].fieldDC = 0;
-
- strcpy(fieldList[3].fieldName, "HIRED");
- fieldList[3].fieldType = 'D';
- fieldList[3].fieldLen = 8; // date field type must be 8.0
- fieldList[3].fieldDC = 0;
-
- strcpy(fieldList[4].fieldName, "DEPT");
- fieldList[4].fieldType = 'C';
- fieldList[4].fieldLen = 6;
- fieldList[4].fieldDC = 0;
- }
-
-